#include <stdarg.h>
#include "../include/kernel.h"
#include "../include/kasm.h"
#include "../include/io.h"
#include "../include/string.h"
#include "../include/defs.h"

extern int stdout;
extern int stderr;
extern int stdin;
extern int CurrentPID;


static void printInt(int num, int * qttyPrinted);
static void printHexa(int num, int * qttyPrinted);
static void printString(const char * string, int * qttyPrinted);

int
getchar(void)
{
    int key = -1;
    int readDone;
    PROCESS* proc;
    proc=GetProcessByPID(CurrentPID);
    _Sti();
    while( !read(stdin, (void *)&key, 1) || key == -1)
    {
        /* Hasta que se aprete una tecla */
//        __asm__ __volatile__("hlt");

        if (proc->blocked==0)
            proc->blocked=1;
    }

    return key;
}

int
putchar(int c)
{
    return write(stdout, (const void *)&c, 1);
}

int
puts(const char * s)
{
    int len = strlen(s);
    /* espacio para el espacio del string + el \n y el \0, el
    \n va porque asi es el funcionamiento real de puts */
    char aux[len + 2];

    strncpy(aux, s, len);
    aux[len + 1] = '\n';

    /* escribe s y \n al final pero no el \0 en pantalla! */
    return write(stdout, (const void *)s, len + 1);
}

int
printf(const char * format, ...)
{
    va_list ap;
    const char * p, * sval;
    int ival, pchars = 0;

    if (format == NULL)
        return 0;

    va_start(ap, format);

    for (p = format; *p ; p++)
    {
        if (*p != '%')
        {
            putchar(*p);
            pchars++;
        }
        else
        {
            switch(*++p)
            {
                case 'd':
                        ival = va_arg(ap, int);
                        printInt(ival, &pchars);
                        break;

                case 's':
                        sval = va_arg(ap, char *);
                        printString(sval, &pchars);
                        break;

                case 'c':
                        ival = va_arg(ap, int);
                        putchar(ival);
                        pchars++;
                        break;

                case 'x':
                        ival = va_arg(ap, int);
                        printHexa(ival, &pchars);
                        break;
                default:
                        putchar(*p);
                        pchars++;
            }
        }
    }
    va_end(ap);
    return pchars;
}

static void
printHexa(int num, int * qttyPrinted)
{
    if (num < 0)
    {
        putchar('-');
        num = -num;
        *qttyPrinted++;
    }

    if ( (num / 16) > 0 )
        printHexa(num/16, qttyPrinted);

    if (num%16 < 10)
        putchar( (num%16)+'0');
    else
        putchar((num%16)-10+'A');

    *qttyPrinted++;

    return;
}

static void
printString(const char * string, int * qttyPrinted)
{
    if (string == NULL)
        return;

    for (string ; *string ; string++, *qttyPrinted++)
        putchar(*string);

    return;
}

static void
printInt(int num, int * qttyPrinted)
{
    if (num < 0)
    {
        putchar('-');
        num = -num;
        *qttyPrinted++;
    }

    if ( (num / 10) > 0 )
        printInt(num/10, qttyPrinted);

    putchar(num % 10 + '0');
    *qttyPrinted++;

    return;
}


unsigned long
inportl (unsigned short _port)
{
    unsigned long rv;
    __asm__ __volatile__ ("inl %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;
}

void
outportl (unsigned short _port, unsigned long _data)
{
    __asm__ __volatile__ ("outl %1, %0" : : "dN" (_port), "a" (_data));
}


/* Fuente: http://www.osdever.net/bkerndev/Docs/printing.htm */
void
inportb (unsigned short _port, unsigned char * rv)
{
    unsigned char aux;

    aux = (*rv);
    __asm__ __volatile__ ("inb %1, %0" : "=a" (aux) : "dN" (_port));

    (*rv) = aux;
    return;
}

/* Fuente: http://www.osdever.net/bkerndev/Docs/printing.htm */
void
outportb (unsigned short _port, unsigned char _data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

unsigned char
readCMOS(unsigned char addr)
{
   unsigned char r;

   ioOut((unsigned short)0x70, addr);
   __asm__ __volatile__ ("jmp 1f; 1: jmp 1f;1:");
   ioIn(&r, (unsigned short)0x71);
   __asm__ __volatile__ ("jmp 1f; 1: jmp 1f;1:");
   return r;
}

unsigned short inw(unsigned short port)
{
    unsigned short ret;
    __asm__ __volatile__ ("inw %1, %0" : "=a" (ret) : "dN" (port));
    return ret;
}

void outw(unsigned short port, unsigned short val)
{
    __asm__ __volatile__("outw %1, %0" : : "dN" (port), "a" (val));
}
